import { publishUploadFilePost } from '@/api'
import { CloudUploadOutline } from '@vicons/ionicons5';
import type { FormInst, UploadCustomRequestOptions, } from 'naive-ui';
import {
	NButton,
	NDrawer,
	NDrawerContent,
	NForm,
	NFormItem,
	NIcon,
	NImage,
	NInput,
	NInputNumber,
	NRadio,
	NRadioGroup,
	NSelect,
	NSpace,
	NSwitch,
	NUpload,
} from 'naive-ui';
import type { Placement } from 'naive-ui/es/drawer/src/DrawerBodyWrapper';
import type { FormItemRule, LabelPlacement } from 'naive-ui/es/form/src/interface';
import type { SelectMixedOption } from 'naive-ui/es/select/src/interface';
import type { CSSProperties } from 'vue';
import { nextTick, ref } from 'vue';

interface FormModel {
	id: number | string | undefined | null;

	[key: string]: any;
}

type FormItemType =
	| 'input'
	| 'input-number'
	| 'upload'
	| 'select'
	| 'textarea'
	| 'switch'
	| 'radio-group';

export type FormItems = FormItem[];

export interface FormItem {
	type: FormItemType;
	key: string;
	label: string;
	rule?: FormItemRule | FormItemRule[];
	placeholder?: string;
	// upload options
	accept?: string;
	// [select, radio-group] options
	options?: SelectMixedOption[];
	// [input, textarea] options
	maxLength?: string | number;
	// input options
	slots?: Record<string, (data: any) => any>;
	// switch options
	checkedValue?: string | boolean | number;
	unCheckedValue?: string | boolean | number;
}

interface IProps {
	defaultValue: FormModel;
	formItems: FormItem[];
	postRequestPromise: (params: any) => Promise<any>;
	putRequestPromise: (params: any) => Promise<any>;
	width?: number | string;
	placement?: Placement;
	closable?: boolean;
	bodyContentStyle?: CSSProperties;
	labelWidth?: string | number;
	labelPlacement?: LabelPlacement;
	rowKey?: string;
	updateFields?: Array<{ modelKey: string; dataKey: string }>;
	title?: string;
}

const active = ref<boolean>(false);
const submitLoading = ref<boolean>(false);
const formRef = ref<FormInst | null>(null);
const model = ref<FormModel>({id: null});
let onShow: (item?: any) => void;
export default function CreateDrawer(props: IProps, context: any) {
	const {slots, emit} = context;
	const {
		rowKey = 'id',
		width = 500,
		placement = 'right',
		closable = true,
		labelWidth = 130,
		labelPlacement = 'left',
		defaultValue,
		bodyContentStyle = undefined,
		formItems,
		postRequestPromise,
		putRequestPromise,
		updateFields,
		title,
	} = props;
	model.value = {...defaultValue};
	const onClose = () => {
		active.value = false;
	};
	const onResetForm = () => {
		Object.keys(model.value).forEach((key) => {
			model.value[key] = defaultValue[key];
		});
	};
	const onSetValue = (key: string, val: any) => {
		model.value[key] = val;
	};
	onShow = async (item?: any) => {
		active.value = true;
		if (item) {
			nextTick(() => {
				Object.keys(model.value).forEach((key) => {
					if (key === 'id') {
						onSetValue(key, item[rowKey]);
					} else {
						onSetValue(key, item[key]);
					}
				});
			});
		} else {
			onResetForm();
		}
	};
	const onUpload = async (
		{file, onFinish, onError}: UploadCustomRequestOptions,
		field = 'avatar',
	) => {
		const formData = new FormData();
		formData.append('files', file.file as File);
		const handle = window.$message.loading('正在上传');
		const {data: url} = await publishUploadFilePost(formData);
		handle.destroy();

		if (url) {
			model.value[field] = url;
			window.$message.success('上传成功');
			formRef.value?.validate();
			onFinish();
		} else {
			onError();
		}
	};
	const onSubmit = () => {
		formRef.value?.validate(async (errors) => {
			if (!errors) {
				const request = model.value.id === null ? postRequestPromise : putRequestPromise;
				const params = {
					...model.value,
				};
				submitLoading.value = true;
				const {data} = await request(params);
				if (model.value.id === null) {
					params.id = typeof data === 'number' ? data : null;
				}
				submitLoading.value = false;
				if (data) {
					window.$message.success('操作成功');
					onClose();
					emit('submit');
				}
			}
		});
	};

	const HFormItems = () => {
		return formItems.map((item) => {
			const slotsMap: any = {};
			if (item.slots) {
				Object.keys(item.slots).forEach((i) => {
					slotsMap[i] = () => item.slots?.[i]?.(model.value);
				});
			}
			return (
				<NFormItem label={item.label} rule={item.rule} path={item.key}>
					{item.type === 'input' && (
						<NInput
							value={model.value[item.key]}
							clearable={true}
							placeholder={item.placeholder}
							maxlength={item.maxLength}
							onUpdateValue={(val) => onSetValue(item.key, val)}
						>
							{{
								...slotsMap,
							}}
						</NInput>
					)}
					{item.type === 'input-number' && (
						<NInputNumber
							value={model.value[item.key]}
							clearable={true}
							placeholder={item.placeholder}
							style={{width: '100%'}}
							onUpdateValue={(val) => onSetValue(item.key, val)}
						>
							{{
								...slotsMap,
							}}
						</NInputNumber>
					)}
					{item.type === 'switch' && (
						<NSwitch
							value={model.value[item.key]}
							checkedValue={item.checkedValue}
							uncheckedValue={item.unCheckedValue}
							onUpdateValue={(val) => onSetValue(item.key, val)}
						>
							{{
								...slotsMap,
							}}
						</NSwitch>
					)}
					{item.type === 'select' && (
						<NSelect
							value={model.value[item.key]}
							options={item.options}
							clearable={true}
							placeholder={item.placeholder}
							style={{width: '100%'}}
							onUpdateValue={(val) => onSetValue(item.key, val)}
						>
							{{
								...slotsMap,
							}}
						</NSelect>
					)}
					{item.type === 'upload' && (
						<div>
							<NUpload
								accept={item.accept}
								customRequest={(options) => onUpload(options, item.key)}
								showFileList={false}
							>
								<NButton type={'primary'}>
									{{
										icon: () => (
											<NIcon>
												<CloudUploadOutline/>
											</NIcon>
										),
										default: () => '点击上传',
									}}
								</NButton>
							</NUpload>
							{model.value[item.key] && (
								<NImage src={model.value[item.key]} width={100} style={{marginTop: '20px'}}/>
							)}
						</div>
					)}
					{item.type === 'textarea' && (
						<NInput
							type={'textarea'}
							maxlength={item.maxLength}
							value={model.value[item.key]}
							clearable={true}
							placeholder={item.placeholder}
							onUpdateValue={(val) => onSetValue(item.key, val)}
						>
							{{
								...slotsMap,
							}}
						</NInput>
					)}
					{item.type === 'radio-group' && (
						<NRadioGroup
							value={model.value[item.key]}
							name={item.key}
							onUpdateValue={(val) => onSetValue(item.key, val)}
						>
							<NSpace>
								{item.options &&
									item.options.map((i, idx) => {
										return (
											<NRadio
												key={idx}
												value={
													typeof i.value === 'number'
														? (i.value as number)
														: typeof i.value === 'string'
															? (i.value as string)
															: (i.value as boolean)
												}
											>
												{i.label}
											</NRadio>
										);
									})}
								{/* <NRadio value={item.options?.[0].value as number}>{item.options?.[0].label}</NRadio>
                <NRadio value={item.options?.[1].value as number}>{item.options?.[1].label}</NRadio> */}
							</NSpace>
						</NRadioGroup>
					)}
				</NFormItem>
			);
		});
	};
	const HForm = () => {
		return (
			<NForm
				ref={formRef}
				labelWidth={labelWidth}
				labelPlacement={labelPlacement}
				model={model.value}
			>
				{HFormItems()}
			</NForm>
		);
	};
	slots.default = HForm;
	const HFooter = () => {
		return (
			<NSpace
				style={{
					position: 'absolute',
					bottom: '16px',
					right: '24px',
					height: '34px',
					textAlign: 'right',
				}}
			>
				<NButton type={'default'} style={{width: '120px'}} onClick={onClose}>
					取消
				</NButton>
				<NButton
					type={'primary'}
					style={{width: '120px'}}
					loading={submitLoading.value}
					onClick={onSubmit}
				>
					确认
				</NButton>
			</NSpace>
		);
	};
	slots.footer = HFooter;

	return (
		<NDrawer
			show={active.value}
			width={width}
			placement={placement}
			onMaskClick={onClose}
			onUpdateShow={onClose}
			onEsc={onClose}
		>
			<NDrawerContent
				closable={closable}
				title={
					title
						? title
						: model.value.id === null ? '添加' : '编辑'
				}
				bodyContentStyle={bodyContentStyle}
			>
				{slots.default()}
				{slots.footer()}
			</NDrawerContent>
		</NDrawer>
	);
}

export { onShow };
